package org.dydl.common.config;

import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.dydl.common.hibernate.naming.strategy.HibernateNamingStrategy;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.alibaba.druid.pool.DruidDataSource;

@Configuration
@EnableTransactionManagement
public class JPAConfig {

	/**
	 * 数据库用户名
	 */
	@Value("${jdbc.username}")
	private String username;

	/**
	 * 数据库密码
	 */
	@Value("${jdbc.password}")
	private String password;

	/**
	 * 连接数据库的url
	 */
	@Value("${jdbc.url}")
	private String url;

	@Value("${dao.packagesToScan}")
	private String packagesToScan;

//	@Value("${hibernate.hbm2ddl.auto}")
//	private String hibernateHbm2ddl;
	
	@Bean
	public DataSource dataSource() {
		System.out.println();
		DruidDataSource dataSource = new DruidDataSource();
		// dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		// //这一项可配可不配，如果不配置druid会根据url自动识别dbType，然后选择相应的driverClassName
		dataSource.setUrl(url); // 连接数据库的url
		dataSource.setUsername(username); // 连接数据库的用户名
		dataSource.setPassword(password); // 连接数据库的密码
		dataSource.setInitialSize(10); // 初始化时建立物理连接的个数。初始化发生在显示调用init方法，或者第一次getConnection时,缺省值为:0
		dataSource.setMinIdle(10); // 最小连接池数量,缺省值为:8
		dataSource.setMaxActive(50); // 最大连接池数量,缺省值为:8
		dataSource.setMaxWait(60000); // 获取连接时最大等待时间，单位毫秒。配置了maxWait之后，缺省启用公平锁，并发效率会有所下降，如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
		dataSource.setTimeBetweenConnectErrorMillis(60000);
		dataSource.setMinEvictableIdleTimeMillis(300000); // 连接保持空闲而不被驱逐的最小时间
		dataSource.setValidationQuery(" SELECT 'x' "); // 用来检测连接是否有效的sql，要求是一个查询语句，常用select
		dataSource.setTestWhileIdle(true); // 建议配置为true，不影响性能，并且保证安全性。申请连接的时候检测，如果空闲时间大于timeBetweenEvictionRunsMillis，执行validationQuery检测连接是否有效。
		dataSource.setTestOnBorrow(false); // 申请连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能。缺省值为:true
		dataSource.setTestOnReturn(false); // 归还连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能。缺省值:false
		dataSource.setPoolPreparedStatements(false); // 是否缓存preparedStatement，也就是PSCache。PSCache对支持游标的数据库性能提升巨大，比如说oracle。在mysql下建议关闭。缺省值:false
		dataSource.setMaxPoolPreparedStatementPerConnectionSize(20); // 要启用PSCache，必须配置大于0，当大于0时，poolPreparedStatements自动触发修改为true。在Druid中，不会存在Oracle下PSCache占用内存过多的问题，可以把这个数值配置大一些，比如说100,缺省值:-1
		return dataSource;
	}

	@Bean
	public EntityManagerFactory entityManagerFactory() {
		// 负责创建一个适合于仅使用JPA进行数据访问的环境的 EntityManager
		LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
		HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
		// adapter.setGenerateDdl(true);
		adapter.setDatabase(Database.MYSQL);
		adapter.setShowSql(true);

		entityManagerFactory.setJpaVendorAdapter(adapter);
		entityManagerFactory.setDataSource(dataSource());

		// 此处需要注意，若不写或地址填的不对，并且也没有xml的配置，程序就会启动不起来，需要配置实体所在包
		entityManagerFactory.setPackagesToScan(packagesToScan);

		Map<String, Object> propsMap = new HashMap<>();
		propsMap.put("hibernate.format_sql", true);
		propsMap.put("hibernate.ejb.naming_strategy", hibernateNamingStrategy());
//		propsMap.put("hibernate.hbm2ddl.auto","update");
		
		entityManagerFactory.setJpaPropertyMap(propsMap);
		entityManagerFactory.afterPropertiesSet();
		return entityManagerFactory.getObject();
	}

	public PlatformTransactionManager transactionManager() {
		JpaTransactionManager transactionManager = new JpaTransactionManager(entityManagerFactory());
		//propsMap.put("globalRollbackOnParticipationFailure",false);
//		transactionManager.setGlobalRollbackOnParticipationFailure(false);
		return transactionManager;
	}

	@Bean
	public HibernateNamingStrategy hibernateNamingStrategy() {
		return new HibernateNamingStrategy();
	}
}
